using Core;
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

/// <summary>
/// 
/// </summary>
public class ScreenJoystick : MonoBehaviour, IPointerDownHandler,
    IPointerUpHandler, IJoystick
{
    public event Action<Vector2> OnMoveStart;
    public event Action<Vector2> OnMove;
    public event Action OnMoveEnd;

    public Image background;
    public Image thumb;
    public float Percent = 0.3f;
    private RectTransform baseRect;
    private Vector2 mDefault;
    private int mJoystickSettingType;
    private float radius;
    private bool isPointerDown;
    private bool isDown;
    public float GetPercent() => Percent;
    private Vector2 pressPosition;
    private Vector2 lastMousePosition;

    void Awake()
    {
        mDefault = background.rectTransform.anchoredPosition;

        var cachedRectTransform = background.rectTransform;
        radius = cachedRectTransform.sizeDelta.x * 0.5f;
    }

    private void OnEnable()
    {
        baseRect = GetComponent<RectTransform>();
        background.enabled = false;
        background.rectTransform.anchoredPosition = mDefault;
    }

    private void OnDisable()
    {
        background.enabled = false;
        background.rectTransform.anchoredPosition = mDefault;
    }

    public void Update()
    {
        if (isPointerDown)
        {
            OnDrag();
            return;
        }

        var h = Input.GetAxis("Horizontal");
        var v = Input.GetAxis("Vertical");
        if (h == 0 && v == 0)
        {
            if (isDown)
            {
                isDown = false;
                OnUp();
            }
        }
        else
        {
            if (!isDown)
            {
                isDown = true;
                OnDown();
            }

            OnDragDelta(new Vector2(h, v));
        }
    }

    public void SetJoystickType(int type)
    {
        mJoystickSettingType = type;
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        isPointerDown = true;
        pressPosition = Input.mousePosition;
        lastMousePosition = pressPosition;
        if (mJoystickSettingType == 0)
        {
            background.rectTransform.anchoredPosition = ScreenPointToAnchoredPosition(eventData);
        }

        OnDown();
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        isPointerDown = false;

        OnUp();
    }

    public void OnDrag()
    {
        var thumbPosition = (Vector2)Input.mousePosition - pressPosition;
        var delta = new Vector2(thumbPosition.x / radius, thumbPosition.y / radius);
        OnDragDelta(delta);
    }

    private Vector2 ScreenPointToAnchoredPosition(PointerEventData eventData)
    {
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRect, eventData.position, eventData.pressEventCamera, out Vector2 localPoint))
        {
            Vector2 pivotOffset = baseRect.pivot * baseRect.sizeDelta;
            return localPoint - (background.rectTransform.anchorMax * baseRect.sizeDelta) + pivotOffset;
        }

        return Vector2.zero;
    }

    private void OnDown()
    {
        OnMoveStart?.Invoke(pressPosition);

        background.enabled = true;
        thumb.enabled = true;
    }

    private void OnUp()
    {
        OnMoveEnd?.Invoke();

        background.enabled = false;
        background.rectTransform.anchoredPosition = mDefault;
        thumb.rectTransform.anchoredPosition = Vector2.zero;
    }

    private void OnDragDelta(Vector2 delta)
    {
        OnMove?.Invoke(delta);

        var thumbPosition = new Vector2(delta.x * radius, delta.y * radius);

        thumbPosition.x = Mathf.FloorToInt(thumbPosition.x);
        thumbPosition.y = Mathf.FloorToInt(thumbPosition.y);

        if (thumbPosition.magnitude > radius)
        {
            thumbPosition = thumbPosition.normalized * radius;
        }

        thumb.rectTransform.anchoredPosition = thumbPosition;
    }
}